Ext.tree.DWRTreeLoader = function(config) {
	Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);
};

/**
 * Loads tree nodes via DWR
 * @class Ext.tree.DWRTreeLoader
 * @extends Ext.tree.TreeLoader
 */
Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {

	/**
	 * method to load children of the node specified in the parameters
	 * @param {Node} node
	 * @param {function} callback
	 */
	load : function(node, callback) {
		// remove all nodes if necessary
		if (this.clearOnLoad) {
			while (node.firstChild) node.removeChild(node.firstChild);
		}

		// create nodes if preloaded
		if (node.attributes.children) {
			var cs = node.attributes.children;
			for (var i = 0, len = cs.length; i < len; i++) node.appendChild(this.createNode(cs[i]));

			if (typeof callback == "function") callback();
		}
		// call DWR service here
		else if (this.dwrCall) this.requestData(node, callback);
	},

	/**
	 * perfoming the remote call
	 * @param {Node} node
	 * @param {function} callback
	 */
	requestData : function(node, callback) {
		if (this.fireEvent("beforeload", this, node, callback) !== false) {

			// var params = this.getParams(node);

			// prepare DWR call params
			var callParams = new Array();
			var success = this.handleResponse.createDelegate(this, [node, callback], 1);
			var error = this.handleFailure.createDelegate(this, [node, callback], 1);
			callParams.push(node.id);
			callParams.push({
				callback : success,
				errorHandler : error
			});

			this.transId = true;
			// call the service
			this.dwrCall.apply(this, callParams);
		}
		else {
			// if the load is cancelled, make sure we notify the node that we are done
			if (typeof callback == "function") callback();
		}
	},
	
	/**
	 * processing the data retrieved from the service
	 * @param {} response
	 * @param {Node} node
	 * @param {function} callback
	 */
	processResponse : function(response, node, callback) {
		try {
			// walk through the array
			for (var i = 0; i < response.length; i++) {
				// create and append new node
				var n = this.createNode(response[i]);
				if (n) node.appendChild(n);
			}
			// notify callback
			if (typeof callback == "function") callback(this, node);
		}
		catch (e) {
			this.handleFailure(response);
		}
	},

	/**
	 * async rensponse handler
	 * @param {} response
	 * @param {Node} node
	 * @param {function} callback
	 */
	handleResponse : function(response, node, callback) {
		this.transId = false;
		this.processResponse(response, node, callback);
		this.fireEvent("load", this, node, response);
	},

	handleFailure : function(response, node, callback) {
		this.transId = false;
		this.fireEvent("loadexception", this, node, response);
		if (typeof callback == "function") {
			callback(this, node);
		}
	}
});


Ext.namespace('Emp2.tree');

Emp2.tree.DWRTreeLoader = function(config) {
  Emp2.tree.DWRTreeLoader.superclass.constructor.call(this, config);
};

/**
 * Loads tree nodes via DWR
 * @class Emp2.siteman.data.SiteTreeLoader
 * @extends Ext.tree.TreeLoader
 */
Ext.extend(Emp2.tree.DWRTreeLoader, Ext.tree.TreeLoader, {
  tenant : null,
  
  services : {},
  nodeCreators : {},

  /**
   * method to load children of the node specified in the parameters
   * @param {Node} node
   * @param {function} callback
   */
  load : function(node, callback) {
    // remove all nodes if necessary
    if (this.clearOnLoad) {
      while (node.firstChild) node.removeChild(node.firstChild);
    }

    // create nodes if preloaded
    if (node.attributes.children) {
      var cs = node.attributes.children;
      for (var i = 0, len = cs.length; i < len; i++) node.appendChild(this.createNode(cs[i]));

      if (typeof callback == "function") callback();
    }
    // call DWR service here
    else if (this.services) this.requestData(node, callback);
  },

  /**
   * perfoming the remote call
   * @param {Node} node
   * @param {function} callback
   */
  requestData : function(node, callback) {
    if (this.fireEvent("beforeload", this, node, callback) !== false) {

      // prepare DWR call params
      var callParams = new Array();
      if (this.tenant != null) callParams.push(this.tenant);
      callParams.push(node.attributes.data.id);
      callParams.push({
          callback : this.handleResponse.createDelegate(this, [node, callback], 1),
          errorHandler : this.handleFailure.createDelegate(this, [node, callback], 1)
        });

      this.transId = true;
      // call the service
      this.services[node.attributes.type].apply(this, callParams);
    }
    else {
      // if the load is cancelled, make sure we notify the node that we are done
      if (typeof callback == "function") callback();
    }
  },
  
  /**
   * processing the data retrieved from the service
   * @param {} response
   * @param {Node} node
   * @param {function} callback
   */
  processResponse : function(response, node, callback) {
    try {
      // walk through the array
      for (var i = 0; i < response.length; i++) {
        
        var n = this.nodeCreators[node.attributes.type](response[i]);
        if (n) node.appendChild(n);
      }
      // notify callback
      if (typeof callback == "function") callback(this, node);
    }
    catch (e) {
      this.handleFailure(response);
    }
  },

  /**
   * async rensponse handler
   * @param {} response
   * @param {Node} node
   * @param {function} callback
   */
  handleResponse : function(response, node, callback) {
    this.transId = false;
    this.processResponse(response, node, callback);
    this.fireEvent("load", this, node, response);
  },

  handleFailure : function(response, node, callback) {
    this.transId = false;
    this.fireEvent("loadexception", this, node, response);
    if (typeof callback == "function") {
      callback(this, node);
    }
  }
});


Emp2.tree.DWRTreeMultiLoader = function(config) {
  Emp2.tree.DWRTreeMultiLoader.superclass.constructor.call(this, config);
};

/**
 * Loads tree nodes via DWR
 * @class Emp2.tree.DWRTreeMultiLoader
 * @extends Ext.tree.TreeLoader
 */
Ext.extend(Emp2.tree.DWRTreeMultiLoader, Ext.tree.TreeLoader, {
  nodeCreator : null,
  scope : this,

  /**
   * method to load children of the node specified in the parameters
   * @param {Node} node
   * @param {function} callback
   */
  load : function(node, callback) {
    // remove all nodes if necessary
    if (this.clearOnLoad) {
      while (node.firstChild) node.removeChild(node.firstChild);
    }

    // create nodes if preloaded
    if (node.attributes.children) {
      var cs = node.attributes.children;
      for (var i = 0, len = cs.length; i < len; i++) node.appendChild(this.createNode(cs[i]));

      if (typeof callback == "function") callback();
    }
    // call DWR service here
    else this.requestData(0, node, callback);
  },

  /**
   * perfoming the remote call
   * @param {Node} node
   * @param {function} callback
   */
  requestData : function(idx, node, callback) {
    if (this.fireEvent("beforeload", this, node, callback) !== false) {

      // prepare DWR call params
      var callParams = node.attributes.createServiceParam.call(this.scope, node);
      callParams.push({
          callback : this.handleResponse.createDelegate(this, [idx, node, callback], 1),
          errorHandler : this.handleFailure.createDelegate(this, [node, callback], 1)
        });

      this.transId = true;
      // call the service
      node.attributes.service[idx].apply(this.scope, callParams);
    }
    else {
      // if the load is cancelled, make sure we notify the node that we are done
      if (typeof callback == "function") callback();
    }
  },
  
  /**
   * processing the data retrieved from the service
   * @param {} response
   * @param {Node} node
   * @param {function} callback
   */
  processResponse : function(response, node, callback) {
    try {
      // walk through the array
      for (var i = 0; i < response.length; i++) {
        
        var n = this.nodeCreator.call(this.scope, node, response[i]);
        if (n) node.appendChild(n);
      }
    }
    catch (e) {
      this.handleFailure(response);
    }
  },

  /**
   * async rensponse handler
   * @param {} response
   * @param {Node} node
   * @param {function} callback
   */
  handleResponse : function(response, idx, node, callback) {
    this.transId = false;
    this.processResponse(response, node, callback);
    this._loop(response, idx, node, callback);
  },
  
  _loop : function(response, idx, node, callback) {
    idx++;
    if (node.attributes.service.length > idx) {
        this.requestData(idx, node, callback);
    } else {
        // notify callback
        if (typeof callback == "function") callback(this, node);
        this.fireEvent("load", this, node, response);
    }
  },

  handleFailure : function(response, node, callback) {
    this.transId = false;
    this.fireEvent("loadexception", this, node, response);
    if (typeof callback == "function") {
      callback(this, node);
    }
  }
});

Ext.namespace("Ext.ux.data");
 
/**
 * @class Ext.ux.data.DwrProxy
 * @extends Ext.data.DataProxy
 * @author loeppky
 * An implementation of Ext.data.DataProxy that uses DWR to make a remote call.
 * Note that not all of Ext.data.DataProxy's configuration options make sense for Ext.ux.data.DwrProxy.
 * The following constructor sample code contains all the available options that can be set:
 * <code><pre>
 *	new Ext.ux.data.DwrProxy({
 *		// Defined by Ext.data.DataProxy
 *		apiActionToHanderMap : {
 *			read : {
 * 				dwrFunction : DwrInterface.read,
 *				// Define a custom function that passes the paging parameters to DWR.
 *				getDwrArgsFunction : function(request) {
 *					var pagingParamNames = this.store.paramNames;
 *					var params = request.params;
 *					return [params[pagingParamNames.start], params[pagingParamNames.limit]];
 *				},
 *				// The scope is set to "this" so that this store's paging parameter names can be accessed.
 *				getDwrArgsScope : this
 *			},
 *			// These aren't needed if only doing reading.
 *			create : {
 *				// Use the default function which will set the DWR args to an array of all the objects to create.
 *				dwrFunction : DwrInterface.create
 *			}, 
 *			update : {
 *				dwrFunction : DwrInterface.update
 *			}, 
 *			destroy : {
 *				dwrFunction : DwrInterface.destroy,
 *				// Define a custom function to pass a login and password, in addition to the objects to delete.
 *				getDwrArgsFunction : function(request, recordDataArray) {
 *					return [recordDataArray, this.login, this.password];
 *				}
 *				getDwrArgsScope : this
 *			}
 *		}
 *	});
 * </pre></code> 
 * @constructor
 * @param {Object} config The config object.
 */
Ext.ux.data.DwrProxy = function(config) {
 
	if (!config || !config.apiActionToHandlerMap) {
		throw new Exception('"apiActionToHandlerMap" is not defined within config.');
	}
 
	// Construct Ext.ux.data.DwrProxy.ActionHandlers from any configs objects.
	this.apiActionToHandlerMap = {};
	Ext.iterate(Ext.data.Api.actions, function(action) {
		var actionHandlerConfig = config.apiActionToHandlerMap[action];
		if (actionHandlerConfig) {
			actionHandlerConfig.action = action;
			this.apiActionToHandlerMap[action] = new Ext.ux.data.DwrProxy.ActionHandler(actionHandlerConfig);
		}
	}, this);
 
	// Ext.data.DataProxy requires that an API action be defined under the "api" key.
	// If it isn't, an Ext.data.DataProxy.Error is thrown.
	// To avoid this, api is set to apiActionToHandlerMap since they share the same keys ("create", "read", "update", and "destroy").
	config.api = this.apiActionToHandlerMap;
 
	Ext.ux.data.DwrProxy.superclass.constructor.call(this, config);
};
Ext.extend(Ext.ux.data.DwrProxy, Ext.data.DataProxy, {
 
	/**
	 * @cfg {Object} apiActionToHandlerMap.
	 * A map of {@link Ext.data.Api} actions to corresponding {@link Ext.ux.data.DwrProxy.ActionHandler}s.
	 * Note: this option is very similar to {@link Ext.data.DataProxy#api}, but since the values need to be different, 
	 * this new option is created so as not to create confusion.  The name of this option is also more clear.
	 */
	apiActionToHandlerMap : {},
 
	/**
	 * DwrProxy implementation of {@link Ext.data.DataProxy#doRequest}.
	 * This implementation attempts to mirror {@link Ext.data.HttpProxy#doRequest} as much as possible.
	 * The getDwrArgsFunction is called for the corresponding action, 
	 * and then a request is made for the dwrFunction that corresponds with the provided action.
	 * See {@link Ext.data.DataProxy#request} for the parameter descriptions.
	 * @private
	 */
	doRequest : function(action, records, params, reader, callback, scope, options) {
		var request = new Ext.ux.data.DataProxy.Request(action, records, params, reader, callback, scope, options);
		var apiActionHandler = this.apiActionToHandlerMap[action];
		if (!apiActionHandler) {
			throw new Exception('No API Action Handler defined for action: ' + action);
		}
 
		var dwrArgs = apiActionHandler.getDwrArgsFunction.call(
			apiActionHandler.getDwrArgsScope, request, this.getRecordDataArray(records), this.getRecordDataBeforeUpdateArray(records)) || [];
		dwrArgs.push(this.createCallback(request));
		apiActionHandler.dwrFunction.apply(Object, dwrArgs); // the scope for calling the dwrFunction doesn't matter, so we simply set it to Object.
	},
 
	/**
	 * @param {Ext.data.Record[]} records The {@link Ext.data.Record}s to pull the data out of.
	 * @return {Object[]} Array containing the result of {@link Ext.data.Record#data} for each {@link Ext.data.Record}.
	 * This is used so the raw {@link Ext.data.Record}s are not sent to DWR, since they have fields the DWR DTO won't be expecting.
	 */
	getRecordDataArray : function(records) {
		return Ext.pluck(records, 'data') || [];
	},
 
	/**
	 * @param {Ext.data.Record[]} records The {@link Ext.data.Record}s that have been updated to get their pre-upadate data from.
	 * @return {Object[]} Array containing the {@link Ext.data.Record#data} before it was updated.
	 * This is used so the raw {@link Ext.data.Record}s are not sent to DWR, since they have fields the DWR DTO won't be expecting.
	 */
	getRecordDataBeforeUpdateArray : function(records) {
		var recordDataBeforeUpdate = [];
		Ext.each(records, function(record) {
			// Create the record data as it existed before it was updated.
			recordDataBeforeUpdate.push(Ext.apply({}, record.modified, record.data));
		});
		return recordDataBeforeUpdate;
	},
 
	/**
	 * Helper method for doRequest which returns a callback function for a DWR request.
	 * The returned callback function in turn invokes the callback function within the provided {Ext.ux.data.DataProxy.Request}.
	 * This mirrors HttpProxy#createCallsback.
	 * DWR is unique though in that it allows one to define a callback function for success and callback function for an exception.
	 * This exceptionHandler callback parallels Ext's "response exception" case.
	 * This method thus returns two callback functions groupded as a single object that can be appended to the DWR function arguments as required by DWR.
	 * @param {Ext.ux.data.DataProxy.Request} request The arguments passed to {@link #doRequest}.
	 * @private
	 */
	createCallback : function(request) {
		return {
			callback: function(response){
				if (request.action === Ext.data.Api.actions.read) {
					this.onRead(request, response);
				} else {
					this.onWrite(request, response);
				}
			}.createDelegate(this),
			exceptionHandler : function(message, exception) {
				// The event is supposed to pass the response, but since DWR doesn't provide that to us, we pass the message.
				this.handleResponseException(request, message, exception);
			}.createDelegate(this)
		};
	},
 
	/**
	 * Helper method for createCallback for handling the read action.
	 * After creating records from the provided response, it calls the callback function within the provided {Ext.ux.data.DataProxy.Request}.
	 * This mirrors HttpProxy#onRead.
	 * @param {Ext.ux.data.DataProxy.Request} request The arguments passed to {@link #doRequest}.
	 * @param {Object} response The response from the DWR call.  This should be an Object which can be converted to {@link Ext.data.Records}.
	 * @private
	 */
	onRead : function(request, response) {
		var readDataBlock;
		try {
			// Call readRecords() instead of read because read() will attempt to decode JSON to create an Object,
			// but as this point DWR has already created an Object.
			readDataBlock = request.reader.readRecords(response);
		} catch(e) {
			return this.handleResponseException(request, response, e);
		}
		if (readDataBlock.success === false) {
			this.fireEvent("exception", this, 'remote', request.action, request.options, response, null);
		} else {
			this.fireEvent("load", this, request, request.options);
		}
		request.callback.call(request.scope, readDataBlock, request.options, readDataBlock.success);
	},
 
	/**
	 * Helper method for createCallback for handling the create, update, and delete actions.
	 * This mirrors HttpProxy#onWrite
	 * @param {Ext.ux.data.DataProxy.Request} request The arguments passed to {@link #doRequest}.
	 * @param {Object} response The response from the DWR call.  This should be an Object which can be converted to {@link Ext.data.Records}.
	 * @private
	 */
	onWrite : function(request, response) {
		var readDataBlock;
		try {
			readDataBlock = request.reader.readResponse(request.action, response);
		} catch (e) {
			return this.handleResponseException(request, response, e);
		}
		if (readDataBlock.success === false) {
			this.fireEvent("exception", this, 'remote', request.action, request.options, response, request.records);
		} else {
			this.fireEvent("write", this, request.action, readDataBlock.data, readDataBlock, request.records, request.options);
		}
		request.callback.call(request.scope, readDataBlock.data, readDataBlock, readDataBlock.success);
	},
 
	/**
	 * @param {Ext.ux.data.DataProxy.Request} request The arguments passed to {@link #doRequest}.
	 * @param {Object} response The response from the DWR call.
	 * @param {Object} exception Exception that was thrown processing the request.
	 */
	handleResponseException : function(request, response, exception) {
		this.fireEvent("exception", this, 'response', request.action, request.options, response, exception);
		request.callback.call(request.scope, null, request.options, false);
	}
});
 
/**
 * @class Ext.ux.data.DwrProxy.ActionHandler
 * Encapsulates the parameters passed to {@link Ext.data.DataProxy#request}.
 * @constructor
 * @param {Object} config The config object.
 * @cfg {String} action [Required] The {@link Ext.data.Api} action this handler is for.
 * @cfg {Function} dwrFunction [Required] The DWR-generated function to call for the action. 
 * @cfg {Function} getDwrArgsFunction [Optional] Function to call to generate the arguments for the dwrFunction.
 * This {@link Function} will be passed:
 * - {@link Ext.ux.data.DataProxy.Request} This is useful for all action.
 * - {@link Ext.data.Record#data}s to write with their current (dirty) values.
 *   This is useful for all write actions.
 * - {@link Ext.data.Record#data}s to write with the values before any changes were made.
 *   This is only useful for updates.
 * The getDwrArgsFunction must return an Array of arguments in the order needed by the dwrFunction.
 * This class will generate the DWR callback function (the final argument passed to the dwrFunction).
 * If no getDwrArgsFunction is defined, see {@link #defaultGetDwrArgsFunctions} for defaults.
 * @cfg {Object} getDwrArgsScope [Optional] The scope to execute getDwrArgsFunction.  Defaults to "Object".
 */
Ext.ux.data.DwrProxy.ActionHandler = function(config) {
	Ext.apply(this, config);
	if (!this.action) {
		throw new Exception('"action" is not defined.');
	}
	if (!Ext.data.Api.isAction(this.action)) {
		throw new Exception(this.action + ' is not a valid Ext.data.Api action.');
	}
	if (!this.dwrFunction) {
		throw new Exception('"dwrFunction" is not defined.');
	}
	if (!this.getDwrArgsFunction) {
		this.getDwrArgsFunction = this.defaultGetDwrArgsFunctions[this.action];
	}
	if (!this.getDwrArgsScope) {
		this.getDwrArgsScope = Object;
	}
};
Ext.extend(Ext.ux.data.DwrProxy.ActionHandler, Object, {
 
	/*
	 * Private properties
	 */
	defaultGetDwrArgsFunctions : {
		/**
		 * @return {Array} Empty array, meaning no arguments are passed to the read dwrFunction.
		 * @private
		 */
		read : function() {
			return [];
		},
 
		/**
		 * @param {Ext.ux.data.DataProxy.Request} request
		 * @param {Array} recordDataArray Array of {@link Ext.data.Record#data} to write.
		 * @return {Object[]} The recordDataArray wrapped in an array so the dwrFunction will send one parameter: a list of {@link Ext.data.Record#data}s to create.
		 * @private
		 */
		create : function(request, recordDataArray) {
			return [recordDataArray];
		},
 
		/**
		 * @param {Ext.ux.data.DataProxy.Request} request
		 * @param {Array} recordDataArray Array of {@link Ext.data.Record#data} to write.
		 * @param {Array} recordDataArray Array of {@link Ext.data.Record#data} to update.
		 * @return {Object[]} The oldRecordDataArray and recordDataArray wrapped in an array so the dwrFunction will send two parameters: 
		 * a list of {@link Ext.data.Record#data}s that are to be updated and a list of their corresponding new values.
		 * @private
		 */
		update : function(request, recordDataArray, oldRecordDataArray) {
			return [oldRecordDataArray, recordDataArray];
		},
 
		/**
		 * @param {Ext.ux.data.DataProxy.Request} request
		 * @param {Array} recordDataArray Array of {@link Ext.data.Record#data} to write.
		 * @return {Object[]} The recordDataArray wrapped in an array so the dwrFunction will send one parameter: a list of {@link Ext.data.Record#data}s to destroy.
		 * @private
		 */
		destroy : function(request, recordDataArray) {
			return [recordDataArray];
		}
	}
});
 
Ext.namespace("Ext.ux.data.DataProxy");
/**
 * @class Ext.ux.data.DataProxy.Request
 * Encapsulates the parameters passed to {@link Ext.data.DataProxy#request}.
 * @constructor
 * @param {String} action The crud action type (create, read, update, destroy).  Note: only "read" is currently supported.
 * @param {Ext.data.Record/Ext.data.Record[]} records If action is "read", records will be null.
 * @param {Object} params An object containing properties which are to be used as parameters for the request to the remote server.
 * @param {Ext.data.DataReader} reader The {@link Ext.data.DataReader} object which converts the server response into a "readDataBlock" (the result from calling {@link Ext.data.DataReader#read}).
 * @param {Function} callback A function to be called after the request.
 * The callback is passed the following arguments:<ul>
 * <li>readDataBlock: Data object from calling {@link Ext.data.DataReader#read}.</li>
 * <li>options: The options object (see below)</li>
 * <li>success: Boolean success indicator.</li>
 * </ul>
 * @param {Object} scope The scope in which to call the callback.
 * @param {Object} options An optional argument which is passed to the callback as its second parameter.
 */
Ext.ux.data.DataProxy.Request = function(action, records, params, reader, callback, scope, options) {
	Ext.apply(this, {
		action : action,
		records : records,
		params : params,
		reader: reader,
		callback : callback,
		scope : scope,
		options : options
	});
};




/**
 * @class Ext.data.ObjectReader
 * @extends Ext.data.DataReader
 * Data reader class to create an Array of {@link Ext.data.Record} objects from an array of objects
 * based on mappings in a provided Ext.data.Record constructor.<br><br>
 * <p>
 * Example code:
 * <pre><code>
var RecordDef = Ext.data.Record.create([
   {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
   {name: 'occupation'}                 // This field will use "occupation" as the mapping.
]);
var myReader = new Ext.data.ObjectReader({
   id: "id"                             // The field that provides an ID for the record (optional)
}, RecordDef);
</code></pre>
 * <p>
 * This would consume data like this:
 * <pre><code>
[ {id:1, name:'Bill', occupation:'Gardener'}, {id:2, name:'Ben', occupation:'Horticulturalist'} ]
</code></pre>
 * @cfg {String} id (optional) The field that provides an ID for the record
 * @constructor
 * Create a new ObjectReader
 * @param {Object} meta Metadata configuration options.
 * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a
 * Record subclass created with {@link Ext.data.Record#create}, or an array of objects with which to call
 * Ext.data.Record.create.  See the {@link Ext.data.Record} class for more details.
 */
Ext.data.ObjectReader = function(meta, recordType){
    meta = meta || {};
    Ext.data.ObjectReader.superclass.constructor.call(this, meta, recordType||meta.fields);
};
Ext.extend(Ext.data.ObjectReader, Ext.data.DataReader, {
    /**
     * This method is only used by a DataProxy which has retrieved data from a remote server.
     * <p>
     * Data should be provided in the following structure:
     * <pre><code>
{
  objects : [ { }, { }... ], // An array of objects
  totalSize : 1234           // The total number of records (>= objects.length)
}
</code></pre>
	 * The 'objects' field is required; other fields are optional.
	 * @param {Array} response An object containing an array of objects and meta data.
     * @return {Object} records A data block which is used by an {@link Ext.data.Store} as
     * a cache of Ext.data.Records.
	 * <p>
	 * Note: This implementation is intended as a convienience to simplify writing DataProxy
	 * subclasses and to guide implementations into common field names to return result data.
	 * If these fields are unnatural for a proxy, it may call readRecords() directly and handle
	 * this functionality itself.
     */
    read : function(response){
        if( undefined == response.objects ) {
            throw {message: "ObjectReader.read: Objects not available"};
        }
        var result = this.readRecords(response.objects);
        if ( undefined != response.totalSize )
				result.totalRecords = response.totalSize;
		return result;
    },

    /**
     * Create a data block containing Ext.data.Records from an an array of objects.
	 * @param {Object} objects An array of objects.
     * @return {Object} records A data block which is used by an {@link Ext.data.Store} as
     * a cache of Ext.data.Records.
     */
    readRecords : function(objects){
		var records = [];
		var recordType = this.recordType, fields = recordType.prototype.fields;
    	var idField = this.meta.id;
        for(var i = 0; i < objects.length; i++) {
        	var object = objects[i];
        	var values = {};
        	for(var j = 0; j < fields.length; j++){
	            var field = fields.items[j];
                var v = object[field.mapping || field.name] || field.defaultValue;
	            v = field.convert(v);
	            values[field.name] = v;
	        }
			var id = idField ? object[idField] : undefined;
	        records[records.length] = new recordType(values, id);
	    }
	    return {
	        records      : records,
	        totalRecords : records.length
	    };
    }
});



Ext.data.StringReader = function(meta, recordType){
    meta = meta || {};
    Ext.data.StringReader.superclass.constructor.call(this, meta, recordType||meta.fields);
};

Ext.extend(Ext.data.StringReader, Ext.data.DataReader, {
  read : function(response){
    if( undefined == response.objects ) {
      throw {message: "StringReader.read: Objects not available"};
    }
    var result = this.readRecords(response.objects);
    if ( undefined != response.totalSize )
    result.totalRecords = response.totalSize;
    return result;
  },

  readRecords : function(objects){
    var records = [];
    var recordType = this.recordType, fields = recordType.prototype.fields;
    var idField = this.meta.id;
    for(var i = 0; i < objects.length; i++) {
      var object = objects[i];

      var values = {};
      for(var j = 0; j < fields.length; j++){
        var field = fields.items[j];
        var v = object;
        v = field.convert(v);
        values[field.name] = v;
      }
      var id = idField ? object : undefined;
      records[records.length] = new recordType(values, id);
    }
    return {
        records      : records,
        totalRecords : records.length
    };
  }
});
